//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shp.Runtime.Contract;
using Shp.Runtime.Sitka.ServiceAgent.Entities;
using Shp.Runtime.Sitka.ServiceAgent;
using System.Globalization;
using Shp.Runtime.DataModel.Sitka.Tests.Entities;

namespace Shp.Runtime.DataModel.Sitka.Tests
{
    [TestClass]
    public class PresentationDataModelFixture
    {
		private TenantEntity _tenantMock = Mocks.MockHelper.GetTenant();
        private MetadataInitialize metadataInitializeData;
        private TestableRepositoryFactory factory;

        [TestInitialize]
        public void TestInitialize()
        {
            metadataInitializeData = new MetadataInitialize();
            factory = new TestableRepositoryFactory(metadataInitializeData.TenantId);
            factory.CreateContainers();
            metadataInitializeData.Container = factory.MetadataContainerName;
        }

        [TestCleanup]
        public void TestCleanUp()
        {
            factory.DeleteContainers();
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ShouldNotGetConfiguredLayoutForUnexistingTenant()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            _dataModel.GetConfiguredLayout("UnexistingTenant");
        }

        [TestMethod]
        public void ShouldGetDefaultConfiguredLayout()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias);

            Assert.AreEqual(0, _dataModel.GetConfiguredLayout(_tenantMock.Alias));
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void ShouldNotGetConfiguredLayoutIfCannotParse()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias, "invalidLayout");

            _dataModel.GetConfiguredLayout(_tenantMock.Alias);
        }

        [TestMethod]
        public void ShouldGetCurrentStyleId()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid styleId = Guid.NewGuid();
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias, styleId);

            Assert.AreEqual(styleId, _dataModel.GetCurrentStyleId(_tenantMock.Id));
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ShouldNotGetConfiguredStyleForUnexistingTenant()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            _dataModel.GetConfiguredStyle("UnexistingTenant");
        }

        [TestMethod]
        public void ShouldGetConfiguredStyle()
        {
            string urlMock = @"http://mystyle.com/classic.css";
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid styleId = Guid.NewGuid();
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias, styleId);
            metadataInitializeData.AddStyle(styleId, _tenantMock.Id, "Style1", urlMock);

            Assert.AreEqual(urlMock, _dataModel.GetConfiguredStyle(_tenantMock.Alias));
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ShouldNotGetMainMenuForUnexistingTenant()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            _dataModel.GetMainMenu("UnexistingTenant", true);
        }
        
        [TestMethod]
        public void ShouldGetOneSingleMainMenu()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid mainMenuId = Guid.NewGuid();
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias);
            metadataInitializeData.AddMainMenu(mainMenuId, _tenantMock.Id, "MockMenuPublic", @"http://public.mockurl.com", true, 1);
            metadataInitializeData.AddMainMenu(Guid.NewGuid(), _tenantMock.Id, "MockMenuPrivate", @"http://private.mockurl.com", false, 1);

            StringPair[] result = _dataModel.GetMainMenu(_tenantMock.Alias, true);

            Assert.AreEqual(1, result.Length);
            Assert.AreEqual("MockMenuPublic", result[0].Key);
            Assert.AreEqual(@"http://public.mockurl.com", result[0].Value);
        }

        [TestMethod]
        public void ShouldGetNoneMainMenu()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid mainMenuId = Guid.NewGuid();
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias);

            StringPair[] result = _dataModel.GetMainMenu(_tenantMock.Alias, true);
            Assert.AreEqual(0, result.Length);
        }

        [TestMethod]
        [ExpectedException(typeof(System.Security.SecurityException))]
        public void ShouldNotGetMainMenuWhenDuplicatedPublicMenues()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias);
            metadataInitializeData.AddMainMenu(Guid.NewGuid(), _tenantMock.Id, "MockMenu", @"http://public1.mockurl.com", true, 1);
            metadataInitializeData.AddMainMenu(Guid.NewGuid(), _tenantMock.Id, "MockMenu", @"http://public2.mockurl.com", true, 2);
            metadataInitializeData.AddMainMenu(Guid.NewGuid(), _tenantMock.Id, "MockMenuPrivate", @"http://private.mockurl.com", false, 2);

            StringPair[] result = _dataModel.GetMainMenu(_tenantMock.Alias, true);
        }

        [TestMethod]
        public void ShouldNotGetMainMenuWhenNoPublicOrPrivateMainMenuExists()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), _tenantMock.Alias);

            StringPair[] resultPublic = _dataModel.GetMainMenu(_tenantMock.Alias, true);

            Assert.IsNotNull(resultPublic);
            Assert.AreEqual(0, resultPublic.Length);

            StringPair[] resultPrivate = _dataModel.GetMainMenu(_tenantMock.Alias, false);

            Assert.IsNotNull(resultPrivate);
            Assert.AreEqual(0, resultPrivate.Length);
        }

        [TestMethod]
        public void ShouldGetStyleList()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid classicStyleId=Guid.NewGuid();
            Guid modernStyleId=Guid.NewGuid();
            Guid otherStyleId = Guid.NewGuid();

            metadataInitializeData.AddStyle(classicStyleId, _tenantMock.Id, "MockClassicStyle", @"http://public.mockurl.com/classic.css");
            metadataInitializeData.AddStyle(modernStyleId, _tenantMock.Id, "MockModernStyle", @"http://public.mockurl.com/modern.css");
            metadataInitializeData.AddStyle(otherStyleId, Guid.NewGuid(), "MockStyle", @"http://public.mockurl.com/mock.css");

            KeyValuePair<Guid, string>[] styles = _dataModel.GetStyleList(_tenantMock.Id);

            Assert.IsNotNull(styles);
            Assert.AreEqual(2, styles.Length);
            Assert.IsTrue(styles.Contains(new KeyValuePair<Guid, string>(classicStyleId, @"MockClassicStyle")));
            Assert.IsTrue(styles.Contains(new KeyValuePair<Guid, string>(modernStyleId, @"MockModernStyle")));
            Assert.IsFalse(styles.Contains(new KeyValuePair<Guid, string>(otherStyleId, @"MockStyle")));

            metadataInitializeData.DeleteEntity(classicStyleId.ToString());
            metadataInitializeData.DeleteEntity(modernStyleId.ToString());
            metadataInitializeData.DeleteEntity(otherStyleId.ToString());
        }

        [TestMethod]
        public void ShouldUpdatePresentation()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            int layout = 0;
            int newLayout = 1;
            Guid style = Guid.NewGuid();
            Guid newStyle = Guid.NewGuid();
            metadataInitializeData.AddTenant(_tenantMock.Id.ToString(), layout, style);

            _dataModel.UpdatePresentation(_tenantMock.Id, newLayout, newStyle);

            using (Repository<GenericExtensibleEntity> repository = factory.MetadataRepository)
            {
                GenericExtensibleEntity tenant = repository.GetById(_tenantMock.Id);
                Assert.AreEqual(newStyle.ToString(), tenant.GetFieldValue("Style"));
                Assert.AreEqual(newLayout, int.Parse(tenant.GetFieldValue("Layout"), CultureInfo.InvariantCulture));
            }
        }

        [TestMethod]
        public void ShouldAddStyle()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            string mockName = "MockStyle";
            Uri mockUrl = new Uri(@"http://public.mockurl.com/mock.css");

            _dataModel.AddStyle(_tenantMock.Id, mockName, mockUrl);

            string queryString = string.Format(@"where e.Kind==""Style"" && e[""TenantId""]==""{0}"" ", _tenantMock.Id);
            IEnumerable<GenericExtensibleEntity> styles = factory.MetadataRepository.Search(queryString);

            Assert.IsNotNull(styles);
            Assert.AreEqual(1, styles.Count());
            Assert.AreEqual("Style", styles.First().Kind);
            Assert.AreEqual("MockStyle", styles.First().GetFieldValue("Name"));
            Assert.AreEqual(@"http://public.mockurl.com/mock.css", styles.First().GetFieldValue("Url"));
        }

        [TestMethod]
        public void ShouldGetMainMenuList()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid mainMenuId1 = Guid.NewGuid();
            Guid mainMenuId2 = Guid.NewGuid();
            metadataInitializeData.AddMainMenu(mainMenuId1, _tenantMock.Id, "MockMenuPublic1", @"http://public1.mockurl.com", true, 1);
            metadataInitializeData.AddMainMenu(mainMenuId2, _tenantMock.Id, "MockMenuPublic2", @"http://public2.mockurl.com", true, 2);

            MainMenuItem[] menuItems =_dataModel.GetMainMenuList(_tenantMock.Id);

            Assert.IsNotNull(menuItems);
            Assert.AreEqual(2, menuItems.Length);
            Assert.AreEqual(1,menuItems.Count(menu=>menu.Description=="MockMenuPublic1"));
            Assert.AreEqual(1,menuItems.Count(menu=>menu.Description=="MockMenuPublic2"));

            MainMenuItem menu1=menuItems.Single(menu=>menu.Description=="MockMenuPublic1");
            MainMenuItem menu2=menuItems.Single(menu=>menu.Description=="MockMenuPublic2");

            Assert.AreEqual(@"http://public1.mockurl.com", menu1.Url);
            Assert.AreEqual(@"http://public2.mockurl.com", menu2.Url);
        }

        [TestMethod]
        [ExpectedException(typeof(System.Security.SecurityException))]
        public void ShouldNotUpdateMainMenuWhenDuplicatedMenus()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            MainMenuItem menu1 = new MainMenuItem();
            menu1.Description = "MockMenu";
            menu1.IsPublic = true;
            MainMenuItem menu2 = new MainMenuItem();
            menu2.Description = "MockMenu";
            menu2.IsPublic = true;
            MainMenuItem[] duplicated = {menu1,menu2 };

            _dataModel.UpdateMainMenu(_tenantMock.Id, duplicated);
        }

        [TestMethod]
        public void ShouldUpdateMainMenuAndDeleteExisting()
        {
            PresentationDataModel _dataModel = new PresentationDataModel(factory);
            Guid mainMenuId1 = Guid.NewGuid();
            metadataInitializeData.AddMainMenu(mainMenuId1, _tenantMock.Id, "MockMenuPublic1", @"http://public1.mockurl.com", true, 1);

            MainMenuItem newMenu1 = new MainMenuItem();
            newMenu1.Description = "MockMenuNew1";
            newMenu1.Url = @"http://MockMenuNew1.com/";
            newMenu1.IsPublic = true;
            MainMenuItem newNenu2 = new MainMenuItem();
            newNenu2.Description = "MockMenuNew2";
            newNenu2.Url = @"http://MockMenuNew2.com/"; ;
            newNenu2.IsPublic = false;
            MainMenuItem[] newMenuItems = { newMenu1, newNenu2 };

            _dataModel.UpdateMainMenu(_tenantMock.Id, newMenuItems);

            GenericExtensibleEntity entity = factory.MetadataRepository.GetById(mainMenuId1);
            string queryString = string.Format(@"where e.Kind==""MainMenu"" && e[""TenantId""]==""{0}"" ", _tenantMock.Id);
            IEnumerable<GenericExtensibleEntity> menuItems = factory.MetadataRepository.Search(queryString);
            IOrderedEnumerable<GenericExtensibleEntity> orderedMenuItems = menuItems.OrderBy(menu => menu.GetFieldValue("Ordinal"));

            Assert.IsNull(entity);
            Assert.IsNotNull(menuItems);
            Assert.AreEqual(2, menuItems.Count());
            Assert.AreEqual("MockMenuNew1", orderedMenuItems.First().GetFieldValue("Description"));
            Assert.AreEqual(@"http://MockMenuNew1.com/", orderedMenuItems.First().GetFieldValue("Url"));
            Assert.AreEqual(true, bool.Parse(orderedMenuItems.First().GetFieldValue("IsPublic")));
            Assert.AreEqual(1, int.Parse(orderedMenuItems.First().GetFieldValue("Ordinal"), CultureInfo.InvariantCulture));
            Assert.AreEqual("MockMenuNew2", orderedMenuItems.Last().GetFieldValue("Description"));
            Assert.AreEqual(@"http://MockMenuNew2.com/", orderedMenuItems.Last().GetFieldValue("Url"));
            Assert.AreEqual(false, bool.Parse(orderedMenuItems.Last().GetFieldValue("IsPublic")));
            Assert.AreEqual(2, int.Parse(orderedMenuItems.Last().GetFieldValue("Ordinal"), CultureInfo.InvariantCulture));
        }
    }
}
